/*
 *  uiScene.cpp
 *  trail-map-editor
 *
 *  Created by Giorgio Tino on 3/2/13.
 *  Copyright 2013 __MyCompanyName__. All rights reserved.
 *
 */

#include "ui.h"

using namespace tinyxml2;

//
// uiScene
//

uiScene::uiScene()
: mView(NULL)
, mRoot(new ssgRoot())
{
}

uiScene::uiScene(const char* filename) 
: mView(NULL)
, mRoot(new ssgRoot())
, mContext(new ssgContext())
{	
	this->load(filename);
    
    mContext->setCullface(true) ;
    mContext->makeCurrent() ;
}

uiScene::~uiScene()
{
	// Gotta get rid of all the uiData for each puObject!
	uiCleanUpUserData(mView, true); // recursive
	
	// Delete the view. This will delete all the childs, I hope.
	puDeleteObject(mView);
	mView = NULL;
    
    ssgDelete(mRoot);
    mRoot = NULL;
}

void uiScene::setDelegate(uiSceneDelegate* delegate)
{
    this->delegate = delegate;
}

void uiScene::load(const char* filename)
{
	// unload the previous view, if present.
	if(mView)
	{
		puDeleteObject(mView);
		mView = 0;
	}
	
	if(!filename)
	{
		ulSetError(UL_FATAL, "NULL scene file specified.",filename);
		return;
	}
    
    Log.write(PlainText, "Load scene from file : %s", filename);
	
	XMLDocument doc;
	XMLError error = doc.LoadFile(filename);
	if(error)
	{
		ulSetError(UL_FATAL, "Scene file not found : %s.",filename);
		return;
	}
	
	//
	// Look for the 'scene' node.
	//
	XMLElement* sceneElement = doc.FirstChildElement( "scene" );
	
	if(!sceneElement)
	{
		ulSetError ( UL_FATAL, "Cannot find scene element in configuration %s. scene must be the root element!", filename ) ;
		return;
	}
	
	//
	// Now parse the scene 'settings', if present...
	//
	XMLElement* settingsElement = sceneElement->FirstChildElement("settings");
	
	if(settingsElement)
	{
		// TODO : pase and load settings
	}
	
	//
	// Create the scene 'view'
	//
	XMLElement* viewElement = sceneElement->FirstChildElement("view");
	
	this->mView = uiView::createView(viewElement);
    
    this->mView->setDelegate(this);
}

void uiScene::display(void)
{
//    static sgVec3 eye = {0,0,4000};
//    static sgVec3 look = {0,0,0};
//    static sgVec3 up = {0,0,1};
//    ssgSetFOV     ( 20, 15 ) ;
//    ssgSetNearFar ( 1, 20000 ) ;
//    ssgSetCameraLookAt(eye, look);
    
    glClearColor(.2,.4,.6,1);
    
    ssgCullAndDraw(mRoot);
    
//    glEnable       ( GL_ALPHA_TEST ) ;
//	glEnable       ( GL_BLEND ) ;
//	glAlphaFunc    ( GL_GREATER, 0.1f ) ;
//	glBlendFunc    ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ) ;
    
	puDisplay();
    
//    glDisable      ( GL_ALPHA_TEST ) ;
//	glDisable      ( GL_BLEND ) ;
//	glAlphaFunc    ( GL_ALWAYS, 0.0 ) ;
//	glBlendFunc    ( GL_ONE, GL_ZERO ) ;
}

void uiScene::resize(int w, int h)
{
	glViewport(0, 0, (GLsizei) w, (GLsizei) h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(30.0, (GLfloat) w/(GLfloat) h, 0.0, 30.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

void uiScene::keyUp(unsigned char key, int x, int y)
{
	puKeyboard(key, PU_UP, x, y);
}

void uiScene::keyDown(unsigned char key, int x, int y)
{
	puKeyboard(key, PU_DOWN, x, y);
}

void uiScene::specialUp(int key, int x, int y)
{
	puKeyboard(key + PU_KEY_GLUT_SPECIAL_OFFSET, PU_UP, x, y);
}

void uiScene::specialDown(int key, int x, int y)
{
	puKeyboard(key + PU_KEY_GLUT_SPECIAL_OFFSET, PU_DOWN, x, y);
}

void uiScene::motion(int newx, int newy)
{
	puMouse(newx, newy);
}

void uiScene::passive(int newx, int newy)
{
	puMouse(newx, newy);
}

void uiScene::mouse(int button, int state, int x, int y)
{
	puMouse(button, state, x, y);
}

const puObject* uiScene::findByName(const char* name) const
{
	return this->mView->findByName(name);
}

// uiSceneDelegate
void uiScene::onCallback(const uiView* view, const char* name, puObject* object)
{
    if(this->delegate)
	{
		this->delegate->onCallback(this, view, name, object);
	}
}

void uiScene::onActiveCallback(const uiView* view, const char* name, puObject* object)
{	
	if(this->delegate)
	{
		this->delegate->onActiveCallback(this, view, name, object);
	}
}

void uiScene::onDownCallback(const uiView* view, const char* name, puObject* object)
{	
	if(this->delegate)
	{
		this->delegate->onDownCallback(this, view, name, object);
	}
}